<!doctype html>
<html>

<head>
  <meta charset='utf-8'>
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <meta name="viewport" content="width=device-width">
  <title>Cycle.js - API reference (isolate)</title>

  <!-- Flatdoc -->
  <script src='../support/vendor/jquery.js'></script>
  <script src='../support/vendor/highlight.pack.js'></script>
  <script src='../legacy.js'></script>
  <script src='../flatdoc.js'></script>

  <!-- Algolia's DocSearch main theme -->
  <link href='//cdn.jsdelivr.net/docsearch.js/2/docsearch.min.css' rel='stylesheet' />

  <!-- Others -->
  <script async src="//static.jsbin.com/js/embed.js"></script>

  <!-- Flatdoc theme -->
  <link href='../theme/style.css' rel='stylesheet'>
  <script src='../theme/script.js'></script>
  <link href='../support/vendor/highlight-github-gist.css' rel='stylesheet'>

  <!-- Meta -->
  <meta content="Cycle.js - API reference (isolate)" property="og:title">
  <meta content="A functional and reactive JavaScript framework for predictable code" name="description">

  <!-- Content -->
  <script id="markdown" type="text/markdown" src="index.html">
# Isolate - [source](https://github.com/cyclejs/cyclejs/tree/master/isolate)

A utility function to make scoped dataflow components in Cycle.js.

```
npm install @cycle/isolate
```

See the Cycle.js [documentation on components](http://cycle.js.org/components.html#multiple-instances-of-the-same-component) for further details.

## Example

```js
import isolate from '@cycle/isolate';
import LabeledSlider from './LabeledSlider';

function bmiCalculator({DOM}) {
  let weightProps$ = Rx.Observable.just({
    label: 'Weight', unit: 'kg', min: 40, initial: 70, max: 140
  });
  let heightProps$ = Rx.Observable.just({
    label: 'Height', unit: 'cm', min: 140, initial: 170, max: 210
  });

  // LabeledSlider is a dataflow component
  // isolate(LabeledSlider) is an impure function: it generates
  // a NEW dataflow component every time it is called.
  let WeightSlider = isolate(LabeledSlider);
  let HeightSlider = isolate(LabeledSlider);

  let weightSlider = WeightSlider({DOM, props$: weightProps$});
  let heightSlider = HeightSlider({DOM, props$: heightProps$});

  let bmi$ = Rx.Observable.combineLatest(
    weightSlider.value$,
    heightSlider.value$,
    (weight, height) => {
      let heightMeters = height * 0.01;
      let bmi = Math.round(weight / (heightMeters * heightMeters));
      return bmi;
    }
  );

  return {
    DOM: bmi$.combineLatest(weightSlider.DOM, heightSlider.DOM,
      (bmi, weightVTree, heightVTree) =>
        h('div', [
          weightVTree,
          heightVTree,
          h('h2', 'BMI is ' + bmi)
        ])
      )
  };
}
```

# API


## <a id="isolate"></a> `isolate(component, scope)`

Takes a `component` function and a `scope`, and returns an isolated version
of the `component` function.

When the isolated component is invoked, each source provided to it is
isolated to the given `scope` using `source.isolateSource(source, scope)`,
if possible. Likewise, the sinks returned from the isolated component are
isolated to the given `scope` using `source.isolateSink(sink, scope)`.

The `scope` can be a string or an object. If it is anything else than those
two types, it will be converted to a string. If `scope` is an object, it
represents "scopes per channel", allowing you to specify a different scope
for each key of sources/sinks. For instance

```js
const childSinks = isolate(Child, {DOM: 'foo', HTTP: 'bar'})(sources);
```

You can also use a wildcard `'*'` to use as a default for source/sinks
channels that did not receive a specific scope:

```js
// Uses 'bar' as the isolation scope for HTTP and other channels
const childSinks = isolate(Child, {DOM: 'foo', '*': 'bar'})(sources);
```

If a channel's value is null, then that channel's sources and sinks won't be
isolated. If the wildcard is null and some channels are unspecified, those
channels won't be isolated. If you don't have a wildcard and some channels
are unspecified, then `isolate` will generate a random scope.

```js
// Does not isolate HTTP requests
const childSinks = isolate(Child, {DOM: 'foo', HTTP: null})(sources);
```

If the `scope` argument is not provided at all, a new scope will be
automatically created. This means that while **`isolate(component, scope)` is
pure** (referentially transparent), **`isolate(component)` is impure** (not
referentially transparent). Two calls to `isolate(Foo, bar)` will generate
the same component. But, two calls to `isolate(Foo)` will generate two
distinct components.

```js
// Uses some arbitrary string as the isolation scope for HTTP and other channels
const childSinks = isolate(Child, {DOM: 'foo'})(sources);
```

Note that both `isolateSource()` and `isolateSink()` are static members of
`source`. The reason for this is that drivers produce `source` while the
application produces `sink`, and it's the driver's responsibility to
implement `isolateSource()` and `isolateSink()`.

_Note for Typescript users:_ `isolate` is not currently type-transparent and
will explicitly convert generic type arguments to `any`. To preserve types in
your components, you can use a type assertion:

```ts
// if Child is typed `Component<Sources, Sinks>`
const isolatedChild = isolate( Child ) as Component<Sources, Sinks>;
```

#### Arguments:

- `component: Function` a function that takes `sources` as input and outputs a collection of `sinks`.
- `scope: String` an optional string that is used to isolate each `sources` and `sinks` when the returned scoped component is invoked.

#### Returns:

*(Function)* the scoped component function that, as the original `component` function, takes `sources` and returns `sinks`.


  </script>

  <!-- Initializer -->
  <script>
    Flatdoc.run({
      fetcher: function (callback) {
        callback(null, document.getElementById('markdown').innerHTML);
      },
      highlight: function (code, value) {
        return hljs.highlight(value, code).value;
      },
    });
  </script>

</head>

<body role='flatdoc' class="no-literate">

  

  <div class='header'>
    <div class='left'>
      <h1><a href="/"><img class="logo" src="../img/cyclejs_logo.svg">Cycle.js</a></h1>
      <ul>
        <li><a href='../getting-started.html'>Guide</a></li>
        <li><a href='../api/index.html'>API</a></li>
        <li><a href='../releases.html'>Releases</a></li>
        <li><a href='https://github.com/cyclejs/cyclejs'>GitHub</a></li>
      </ul>
      <input id="docsearch" />
    </div>
    <div class='right'>
      <!-- GitHub buttons: see https://ghbtns.com -->
      <iframe src="https://ghbtns.com/github-btn.html?user=cyclejs&amp;repo=cyclejs&amp;type=watch&amp;count=true"
        allowtransparency="true" frameborder="0" scrolling="0" width="110" height="20"></iframe>
    </div>
  </div>

  <div class='content-root'>
    <div class='menubar'>
      <div class='menu section'>
        
        <div role='flatdoc-menu'></div>
        
      </div>
    </div>
    <div role='flatdoc-content' class='content'></div>
    
  </div>
  

  <script>
    ((window.gitter = {}).chat = {}).options = {
      room: 'cyclejs/cyclejs'
    };
  </script>
  <script src="https://sidecar.gitter.im/dist/sidecar.v1.js" async defer></script>
  <script src='//cdn.jsdelivr.net/docsearch.js/2/docsearch.min.js'></script>
  <script src='../docsearch.js'></script>
</body>

</html>
